//################################################################################
// MIT License
// Copyright (c) 2024 ZhangYihua
//
// Change Logs:
// Date           Author       Notes
// 2020-03-11     ZhangYihua   first version
//
// Description  : 
//################################################################################

module cordic_rotate #(
parameter           DW                      = 16,
parameter           SW                      = 3,
parameter           OUT_REG                 = 1'b1,

// the following parameters are calculated automatically
parameter           XIW                     = DW,
parameter           XOW                     = DW,
parameter           YIW                     = DW,
parameter           YOW                     = DW
) ( 
input                                       rst_n,
input                                       clk,
input                                       cke,

input                                       dir,    // 1'b0: anticlockwise; 1'b1: clockwise
input               [SW-1:0]                sft,    // 0:1; 1:1/2; 2:1/4 .......
input       signed  [XIW-1:0]               xi,
input       signed  [YIW-1:0]               yi,
output      signed  [XOW-1:0]               xo,
output      signed  [YOW-1:0]               yo
);

//################################################################################
// define local varialbe and localparam
//################################################################################
localparam          XNW                     = MAX_F(XIW, XOW);
localparam          YNW                     = MAX_F(YIW, YOW);

wire        signed  [XIW-1:0]               xs;
wire        signed  [YIW-1:0]               ys;
reg         signed  [XNW-1:0]               xn;
reg         signed  [YNW-1:0]               yn;

//################################################################################
// main
//################################################################################

assign xs = (xi>>>sft);
assign ys = (yi>>>sft);

always@(*) begin
    if (dir==1'b0) begin    // increase angle
        xn = xi - ys;
        yn = yi + xs;
    end else begin          // decrease angle
        xn = xi + ys;
        yn = yi - xs;
    end
end

generate if (OUT_REG==1'b1) begin:G_REG
    reg         signed  [XOW-1:0]               xr;
    reg         signed  [YOW-1:0]               yr;

    always@(posedge clk or negedge rst_n) begin
        if (rst_n==1'b0) begin
            xr <=`U_DLY {XOW{1'b0}};
            yr <=`U_DLY {YOW{1'b0}};
        end else if (cke==1'b1) begin
            xr <=`U_DLY xn[0+:XOW];
            yr <=`U_DLY yn[0+:YOW];
        end else
            ;
    end

    assign xo = xr;
    assign yo = yr;
end else begin:G_NREG
    assign xo = xn[0+:XOW];
    assign yo = yn[0+:YOW];
end endgenerate

`include "func_param.v" // refer to MAX_F()

//################################################################################
// ASSERTION
//################################################################################

`ifdef CBB_ASSERT_ON
// synopsys translate_off


// synopsys translate_on
`endif

endmodule
